#ifndef CLEVENT_H
#define	CLEVENT_H

#include <CL/cl.h>
#include "clUtils.h"
#include <algorithm>

struct ClEvent {
	ClEvent() : event(0) { }
	
	ClEvent(cl_event e) : event(e) { }
	
	ClEvent(const ClEvent &other) : event(other.event) {
		CL_CHECK(clRetainEvent(event));
	}
	
	ClEvent& operator = (const ClEvent &other) {
		ClEvent temp(other);
		std::swap(temp.event, event);
		return *this;
	}
	
	~ClEvent() {
		clReleaseEvent(event);
	}
	
	void wait() const {
		CL_CHECK(clWaitForEvents(1, &event));
	}
		
	double getEnqueueToEndSec() const {
		cl_long t = getEventNanos(CL_PROFILING_COMMAND_END) - getEventNanos(CL_PROFILING_COMMAND_QUEUED);
		return t / 1E+9;
	}
	
	double getSubmitToEndSec() const {
		cl_long t = getEventNanos(CL_PROFILING_COMMAND_END) - getEventNanos(CL_PROFILING_COMMAND_SUBMIT);
		return t / 1E+9;
	}
	
	double getStartToEndSec() const {
		cl_long t = getEventNanos(CL_PROFILING_COMMAND_END) - getEventNanos(CL_PROFILING_COMMAND_START);
		return t / 1E+9;
	}
	
private:
	cl_event event;
	
	cl_ulong getEventNanos(cl_profiling_info info) const {
		cl_ulong ret;
		CL_CHECK(clGetEventProfilingInfo(event, info, sizeof(cl_ulong), &ret, NULL));
		return ret;
	}
};

inline void waitAll(size_t count, ClEvent events[]) {
	for (int i = 0; i < count; i++) {
		events[i].wait();
	}
}

#define WAIT_ALL(...) {\
	ClEvent _args[] = { __VA_ARGS__ }; \
	waitAll(sizeof(_args) / sizeof(*_args), _args); \
}

#endif	/* CLEVENT_H */

